﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Diagnostics;
using System.Xml;

namespace LifeFlow.Servicer
{
    public class ServiceMapper : Controller
    {
        public static bool EnforceKey { get; set; }

        public object Call(string controller, string method, string version, string key, string type="")
        {
            var timer = new Stopwatch();
            timer.Start();
            object data = null;
            var v = new ServiceVersion(version);

            var a = _cache.GetAttribute(controller, method, v);

            if ((!a.RequireKey && !EnforceKey) || KeyHandler.IsValid(key))
            {
                data = InvokeMethod(controller, method, v);
            }

            var result = new ServiceResult()
            {
                Result = data
            };
            timer.Stop();
            result.Time = timer.ElapsedMilliseconds;


            switch (type.ToLower())
            {
                case "xml":
                    //TODO
                    return null;
                case "json":
                    return Json(result, JsonRequestBehavior.AllowGet);
                default:
                    return result.Result;
            }
        }

        public ActionResult Describe(string controller, string version, string view, string type, string key)
        {
            var v = new ServiceVersion(version);
            var timer = new Stopwatch();
            timer.Start();
            List<ServiceCache.ServiceCacheItem> data;
            var result = new ServiceResult();

            if (EnforceKey == false || KeyHandler.IsValid(key))
            {
                data = _cache.GetMethods(controller, v);
                result.Result = data.Select(r => r.Attribute.GetDescription(r.Method)).ToList();
            }
            timer.Stop();
            result.Time = timer.ElapsedMilliseconds;

            var ntype = type != null ? type.ToLower() : "Unknown";
            switch (ntype)
            {
                case "xml":
                    var xmlSerializer = new System.Xml.Serialization.XmlSerializer(result.GetType());
                    StringWriter stringWriter = new StringWriter();
                    xmlSerializer.Serialize(stringWriter, result);
                    string serializedXml = stringWriter.ToString();
                    return Content(serializedXml, "text/xml");
                default:
                    return Json(result, JsonRequestBehavior.AllowGet);
            }
        }

        private readonly ServiceCache _cache = new ServiceCache();
        private static IKeyHandler _keyHandler = new InternalKeyHandler();

        public static IKeyHandler KeyHandler
        {
            get { return _keyHandler; }
            set { _keyHandler = value; }
        }

        public static void AddConsumer(ApiConsumer consumer)
        {
            KeyHandler.AddToList(consumer);
        }

        private object InvokeMethod(string service, string method, ServiceVersion version)
        {
            var m = _cache.GetMethod(service, method, version);
            var type = m.ReflectedType;
            var context = Activator.CreateInstance(type, new object[0]);
            var result = m.Invoke(context, new object[0]);

            return result;
        }

        public static void CreateRoute(string name, RouteCollection routes, string controller)
        {
            routes.MapRoute(
                "APIDescription", // Route name
                name + "/describe/{version}/{controller}/{key}", // URL with parameters
                new { controller, action = "Describe", key = UrlParameter.Optional } // Parameter defaults
                );
            routes.MapRoute(
                "API", // Route name
                name + "/{version}/{controller}/{method}/{key}", // URL with parameters
                new { controller, action = "Call", key = UrlParameter.Optional } // Parameter defaults
                );
        }

        public static void Initialize(string path)
        {
            var cache = new ServiceCache();
            cache.CacheServices(path);
        }
    }
}
